package com.ives.launcher.view;

import java.util.HashSet;
import java.util.Set;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Scroller;

import com.ives.launcher.logic.DragContainer;
import com.ives.launcher.util.ILog;

/**
 * 桌面中的第二层容器，与“抽屉”同级，用于装所有的页面（View_Page_Item）
 * 此类主要处理page的滑动切换
 * @author ives
 * 
 */
public class View_Page_Root extends ViewGroup implements DragContainer{
	private static final int Invalid_Index = -1;// 无效下标
	private int currentScreenIndex = Invalid_Index;// 当前屏幕
	private View_Root view_manager;
	public long DragPageinterval = 1000;//拖动页面的至少间隔时间（毫秒）
	/**
	 * 最后一次拖动页面的时间
	 * 在规定时间之内，不可以再进行第二次跨页面的拖动
	 */
	public long lastDragPageTime = 0;
	
	
	public View_Page_Root(Context context) {
		super(context);
	}

	public View_Page_Root(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		addListener();
		currentScreenIndex = 0;
		init(context);
		
	}

	public View_Page_Root(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	private void init(Context context) {
		mScroller = new Scroller(context);
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
		scaleRatioX = 10;
		scaleRatioY = 10;
		// 取得所有的子view
	}
	/**
	 * 切换显示模式：
	 * 包括：1，正常。2，缩略图
	 * @param mode
	 */
	public void setShowModel(int mode){
//		switch(mode){
//		case 2://进行缩放
//			scaleRatioX = 8;
//			
//			break;
//			default://设置成正常
//				scaleRatioX = 10;
//		}
//		for (int i = 0; i < getChildCount(); i++) {
//			((View_Page_Item)getChildAt(i)).setSize(getMeasuredWidth()/10*scaleRatioX, getMeasuredHeight());
//		}
//		onLayout(true, 0, 0,getChildCount()*getMeasuredWidth()/10*scaleRatioX, getMeasuredHeight());
	}
	public int scaleRatioX = 10;//缩放比例，默认为10，不缩放
	 public int scaleRatioY = 10;//缩放比例，默认为10，不缩放
	/**
	 * 布局测量的时候调用，对viewgroup重写的时候要注意
	 */
	@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);   
        final int width = MeasureSpec.getSize(widthMeasureSpec);//取得宽度
        final int height = MeasureSpec.getSize(heightMeasureSpec);//取得gao度
        //将所有的子类设置成同样大小
        final int count = getChildCount();
        this.setMeasuredDimension(width, height);
        for (int i = 0; i < count; i++) {
           // getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        	if(scaleRatioX==10 && scaleRatioY==10)
        	getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        	else{
        		((View_Page_Item)getChildAt(i)).setSize(width/10*scaleRatioX,height/10*scaleRatioY);
        	}
        }
    }
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		if (changed) {//如果改变
			int childLeft = 0;//每个子view的起始left位置
			if(scaleRatioX!=10)childLeft = (getMeasuredWidth()-getMeasuredWidth()/10*scaleRatioX)/2;
			final int childCount = getChildCount();
			for (int i=0; i<childCount; i++) {
				final View childView = getChildAt(i);
				if (childView.getVisibility() != View.GONE) {//如果view的状态为可见
					final int childWidth = childView.getMeasuredWidth();//取得view的宽度
					//特别注意childLeft，这样就把所有的child都依次排开了
					childView.layout(childLeft, 0, childLeft+childWidth, childView.getMeasuredHeight());
					childLeft += childWidth;//依次相加
				}
			}
		}
	}

	/**
	 * 取得当前正在显示的page_item
	 * 
	 * @return
	 */
	public View_Page_Item getCurrentPage_Item() {
		if (Invalid_Index >= currentScreenIndex)
			return null;
		return (View_Page_Item) this.getChildAt(currentScreenIndex);
	}
	/**
	 * 获取指定下标的page
	 * @param index
	 * @return
	 */
	public View_Page_Item getView_Page_ItemForIndex(int index){
		if(index>=0 && index<this.getChildCount())
			return (View_Page_Item) getChildAt(index);
		return null;
	}
	/**
	 * 添加cell到指定页面的指定位置
	 * @param pageIndex
	 * @param cell
	 * @param params
	 */
	public boolean addCellToScreen(int pageIndex,View_Cell cell,View_Page_Item.LayoutParams params){
		if(pageIndex<0 || pageIndex>=this.getChildCount())return false;
		try{
			View_Page_Item page = (View_Page_Item) this.getChildAt(pageIndex);
			page.addView(cell,params);
			return true;
		}catch(IndexOutOfBoundsException e){
			e.printStackTrace();
			return false;
		}
	}

	
	private Scroller mScroller;//滚动辅助类
	private VelocityTracker mVelocityTracker;//速度跟踪器
	
	private static final int TOUCH_STATE_REST = 0;//表示触摸状态为重置,即可以开始新一次滑动
	private static final int TOUCH_STATE_SCROLLING = 1;//表示触摸状态为正在滚动
	
	private static final int SNAP_VELOCITY = 1000;//速度
	
	private int mTouchState = TOUCH_STATE_REST;//当前触摸状态
	private int mTouchSlop;
	private float mLastMotionX;//最后的x
	private float mLastMotionY;//最后的y
	/**
	 * 处理滑动事件
	 */
	@Override
	public void computeScroll() {
		// 如果返回true，表示动画还没有结束
		// 因为前面startScroll，所以只有在startScroll完成时 才会为false
		if (mScroller.computeScrollOffset()) {
			// 产生了动画效果 每次滚动一点
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
		    //刷新View 否则效果可能有误差
			postInvalidate();
		}
	}
	
	/**
	 * 是否对触摸事件进行拦截
	 * 应当拦截屏幕滑动事件
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		final int action = ev.getAction();
		//表示已经开始滑动了，不需要走该Action_MOVE方法了(第一次时可能调用)。拦截该事件
		if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
			return true;
		}

		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {
		case MotionEvent.ACTION_MOVE:
			final int xDiff = (int) Math.abs(mLastMotionX - x);//滑动距离
			//超过了最小滑动距离
			if (xDiff > mTouchSlop) {
				mTouchState = TOUCH_STATE_SCROLLING;
			}
			break;
		case MotionEvent.ACTION_DOWN:
			//记录最后的坐标
			mLastMotionX = x;
			mLastMotionY = y;
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
			break;
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			mTouchState = TOUCH_STATE_REST;
			break;
		}
		return mTouchState != TOUCH_STATE_REST;//如果mTouchState是rest状态就返回false
	}
	/**
	 * 如果要使拖动过程流畅，必须返回true
	 * 在确定屏幕被长按后，返回false
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(View_Root.isLongPress)return false;//如果进入长按状态，就不执行其他操作，将对onClickListener的控制交给View_Root
		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();//重新获得速度跟踪器
		}
		mVelocityTracker.addMovement(event);
		super.onTouchEvent(event);
		//记录手指位置
		float x = event.getRawX();
		float y = event.getRawY();
		
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			//如果屏幕的动画还没结束，你就按下了，我们就结束该动画
			if(mScroller != null){
				if(!mScroller.isFinished()){
					mScroller.abortAnimation();//终止动画
				}
			}
			mLastMotionX = x;
			break ;
		case MotionEvent.ACTION_MOVE:
			int detaX = (int)(mLastMotionX - x );
			scrollBy(detaX, 0);
			mLastMotionX = x ;
			break ;
		case MotionEvent.ACTION_UP:
			final VelocityTracker velocityTracker = mVelocityTracker  ;
			velocityTracker.computeCurrentVelocity(1000);
			
			int velocityX = (int) velocityTracker.getXVelocity() ;
			//滑动速率达到了一个标准(快速向右滑屏，返回上一个屏幕) 马上进行切屏处理
			if (velocityX > SNAP_VELOCITY && currentScreenIndex > 0) {
				snapToScreen(currentScreenIndex - 1);
			}else if(velocityX < -SNAP_VELOCITY && currentScreenIndex < (getChildCount()-1)){//快速向左滑屏，返回下一个屏幕)
				snapToScreen(currentScreenIndex + 1);
			}else{//以上为快速移动的 ，强制切换屏幕
				//我们是缓慢移动的，因此先判断是保留在本屏幕还是到下一屏幕
				snapToDestination();
			}
			
			if (mVelocityTracker != null) {
				mVelocityTracker.recycle();
				mVelocityTracker = null;
			}
			
			mTouchState = TOUCH_STATE_REST ;
			
		    break;
		case MotionEvent.ACTION_CANCEL:
			mTouchState = TOUCH_STATE_REST ;
			break;
		}
		return true ;
	}
	/** 
	 * 获取whichPage的Pager起始x位置，whichPage从0开始计
	 * 提示：超过此位置，页面才滑动到下一个页面
	 * @param whichPage
	 * @return
	 */
	private int getScrollXForPage(int whichPage) {
		return (whichPage * getWidth()) - pageWidthPadding();
	}

	/**
	 * 返回View的 paddingwidth 一半
	 * 如果手指在滑动过程中停止，用于计算到底是返回原页面还是滑动到下一个页面
	 * @return
	 */
	int pageWidthPadding() {
		return ((getMeasuredWidth() - getWidth()) / 2);
	}
	/**
	 * draw子view的时候调用
	 */
	@Override
	protected void dispatchDraw(Canvas canvas) {	// draw the child views
		
		final long drawingTime = getDrawingTime();	// 绘制childView
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			super.drawChild(canvas, getChildAt(i), drawingTime);
		}
		//通知所有监听器
		for (OnScrollListener mListener : mListeners) {	// 自定义接口
			int adjustedScrollX = getScrollX() + pageWidthPadding();
			mListener.onScroll(adjustedScrollX);
			if (adjustedScrollX % getWidth() == 0) {	// scroll finished
				mListener.onViewScrollFinished(adjustedScrollX / getWidth());
			}
		}
	}
	/**
	 * 计算移动到哪个屏幕
	 */
	private void snapToDestination(){
		int destScreen = (getScrollX() + getWidth() / 2 ) / getWidth() ;
		snapToScreen(destScreen);
	}
	/**
	 * 移动到某个屏幕
	 * @param whichScreen
	 */
    public void snapToScreen(int whichScreen){	
	    currentScreenIndex = whichScreen ;//更新当前page编号
	    View_Root.TOUCH_TYPE = View_Root.TOUCH_TYPE_SCROLL_SCREEN;//更新触摸状态
	    if(currentScreenIndex > getChildCount() - 1)
	    	currentScreenIndex = getChildCount() - 1 ;
	    
	    int dx = currentScreenIndex*(getWidth()/10*scaleRatioX) - getScrollX();
	    mScroller.startScroll(getScrollX(), 0, dx, 0,Math.abs(dx) * 3);
	    //背景切换
	    view_manager.setWallpaper(currentScreenIndex, getChildCount());
	    //此时需要手动刷新View 否则没效果
	    getCurrentPage_Item().invalidate();
	   
    }
    /**
     * 拖动某个cell到某个屏幕
     * @param index
     * @param index
     */
	@SuppressLint("ParserError")
	public void DragToScreen(int nowIndex,int targetIndex){
		if(targetIndex<0 || targetIndex>(this.getChildCount()-1))return ;
		if(System.currentTimeMillis()-lastDragPageTime<DragPageinterval)return;//确保此操作需要间隔给定的时间
		 currentScreenIndex = targetIndex ;//更新当前page编号
		    if(currentScreenIndex > getChildCount() - 1)//保证不超出最大范围
		    	currentScreenIndex = getChildCount() - 1 ;
		    int dx = currentScreenIndex*(getWidth()/10*scaleRatioX) - getScrollX();
		    mScroller.startScroll(getScrollX(), 0, dx, 0,Math.abs(dx) * 3);
		    
		    //调用对应页面的回调方法
		    getView_Page_ItemForIndex(nowIndex).onDropOut(view_manager.view_Dragging,  getView_Page_ItemForIndex(targetIndex));
		    getView_Page_ItemForIndex(targetIndex).onDragIn(view_manager.view_Dragging, getView_Page_ItemForIndex(nowIndex));
		    lastDragPageTime = System.currentTimeMillis();
		    view_manager.setWallpaper(currentScreenIndex, getChildCount());
		    //此时需要手动刷新View否则没效果
		    invalidate();
		    //提醒页面drag的进出
	}
	
	@Override
	public void invalidate() {
		super.invalidate();
		for (int i = 0; i < getChildCount(); i++) {
			getChildAt(i).invalidate();
		}
	}


	/**实现滚动过程监听**/
	//所有滚动监听器
		private Set<OnScrollListener> mListeners = new HashSet<OnScrollListener>();		// 监听事件接口
	/**
	 * 设置滚动监听器
	 * @param listener
	 */
	public void addOnScrollListener(OnScrollListener listener) {
		mListeners.add(listener);
	}
	/**
	 * 移除滚动监听器
	 * @param listener
	 */
	public void removeOnScrollListener(OnScrollListener listener) {
		mListeners.remove(listener);
	}

	/** 自定义接口 */
	public static interface OnScrollListener {
		/**
		 * 滑动的过程中，随时传出滑动位置，方便底部指示条动画位置同步
		 * @param scrollX
		 */
		void onScroll(int scrollX);
		/**
		 * 当一次滑动完成的时候调用
		 * @param currentPage
		 */
		void onViewScrollFinished(int currentPage);
	}
	/**
	 * 检查子view是否为正确的类型，并添加index
	 * @param v
	 */
	private void checkAddView(View v){
		if(v instanceof View_Page_Item){
			View_Page_Item item = (View_Page_Item) v;
			item.setIndex(currentScreenIndex+1);
		}else{
			throw new ClassCastException();
		}
	}
	
	@Override
	public void addView(View child) {
		checkAddView(child);
		super.addView(child);
	}

	@Override
	public void addView(View child, LayoutParams params) {
		checkAddView(child);
		super.addView(child, params);
		
	}
	private void addListener(){
		this.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				
			}
		});
		this.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return false;
			}
		});
	}

	/**getter and setter**/
	public View_Root getView_manager() {
		return view_manager;
	}

	public void setView_manager(View_Root view_manager) {
		this.view_manager = view_manager;
	}

	public int getCurrentScreenIndex() {
		return currentScreenIndex;
	}

	public void setCurrentScreenIndex(int currentScreenIndex) {
		this.currentScreenIndex = currentScreenIndex;
	}


	@Override
	public void onDragIn(View view, DragContainer source) {
		getCurrentPage_Item().onDragIn(view, source);
	}

	@Override
	public void onDropOut(View view, DragContainer target) {
		getCurrentPage_Item().onDropOut(view, target);
	}

	@Override
	public void onDropCompleted(View target, boolean success) {
		getCurrentPage_Item().onDropCompleted(target, success);
	}

	@Override
	public boolean disposeDrop(MotionEvent event, View_Drag drag) {
		//判断是否已经跨页，如果跨页，那么调用对应回调方法
		/**判断是否碰到“页面边界”，如果碰到，就调用对应的回调方法，并跳转到对应的页面**/
		if(event.getX()>getCurrentPage_Item().getWidth()-10){
			//跳转到下一个页面
			DragToScreen(getCurrentScreenIndex(),getCurrentScreenIndex()+1);
		}else if(event.getX()<10){
			//跳转到上一个页面
			DragToScreen(getCurrentScreenIndex(),getCurrentScreenIndex()-1);
		}
		getCurrentPage_Item().disposeDrop(event, drag);
		return false;
	}

	@Override
	public int[] findDropCellFinalPosition(int touchX, int touchY,View_Drag drag) {
		return getCurrentPage_Item().findDropCellFinalPosition(touchX, touchY, drag);
	}

	@Override
	public boolean moveToPosition(int x1,int y1,View_Drag drag){
		return getCurrentPage_Item().moveToPosition(x1, y1, drag);
	}

	@Override
	public void setPositionStatus(int x, int y, int w, int h, boolean used) {
		getCurrentPage_Item().setPositionStatus(x, y, w, h, used);
	}

	@Override
	public void removeCell(View_Cell cell) {
		getCurrentPage_Item().removeCell(cell);
	}
	@Override
	public View getChildByPosition(int x,int y){
		return getCurrentPage_Item().getChildByPosition(x, y);
	}
	/**getter  and setter**/
	public int getScaleRatioX() {
		return scaleRatioX;
	}

	public void setScaleRatioX(int scaleRatioX) {
		this.scaleRatioX = scaleRatioX;
	}

	public int getScaleRatioY() {
		return scaleRatioY;
	}

	public void setScaleRatioY(int scaleRatioY) {
		this.scaleRatioY = scaleRatioY;
	}

	@Override
	public boolean checkCanMoveToPosition(int x, int y, View_Drag drag) {
		return getCurrentPage_Item().checkCanMoveToPosition(x, y, drag);
	}

	
	
	

}
